package jsr292.java.lang.invoke;

import jsr292.weaver.Debug;
import jsr292.weaver.opt.OptimizerContext;
import jsr292.weaver.opt.OptimizerSnippets;
import jsr292.weaver.opt.OptimizerVarAllocator;

class MHFilterReturnValue extends MethodHandle {
    private final MethodHandle target;
    private final MethodHandle filter;

    public MHFilterReturnValue(MethodType methodType, MethodHandle target, MethodHandle filter) {
        super(methodType);
        this.target = target;
        this.filter = filter;
    }

    @Override
    public Object $invoke$() throws Throwable {
        return filter.$invoke$(target.$invoke$());
    }
    @Override
    public Object $invoke$(Object o1) throws Throwable {
        return filter.$invoke$(target.$invoke$(o1));
    }
    @Override
    public Object $invoke$(Object o1, Object o2) throws Throwable {
        return filter.$invoke$(target.$invoke$(o1, o2));
    }
    @Override
    public Object $invoke$(Object o1, Object o2, Object o3) throws Throwable {
        return filter.$invoke$(target.$invoke$(o1, o2, o3));
    }
    @Override
    public Object $invoke$(Object o1, Object o2, Object o3, Object o4)
            throws Throwable {
        return filter.$invoke$(target.$invoke$(o1, o2, o3, o4));
    }
    @Override
    public Object $invoke$(Object o1, Object o2, Object o3, Object o4, Object o5)
            throws Throwable {
        return filter.$invoke$(target.$invoke$(o1, o2, o3, o4, o5));
    }
    @Override
    public Object $invoke$(Object o1, Object o2, Object o3, Object o4,
            Object o5, Object o6) throws Throwable {
        return filter.$invoke$(target.$invoke$(o1, o2, o3, o4, o5, o6));
    }
    @Override
    public Object $invoke$(Object o1, Object o2, Object o3, Object o4,
            Object o5, Object o6, Object o7) throws Throwable {
        return filter.$invoke$(target.$invoke$(o1, o2, o3, o4, o5, o6, o7));
    }
    @Override
    public Object $invoke$(Object... rest) throws Throwable {
        return filter.$invoke$(target.$invoke$(rest));
    }
    
    @Override
    public boolean isWeavable(Class<?> classBeingRedefined) {
        return target.isWeavable(classBeingRedefined) &&
               filter.isWeavable(classBeingRedefined);
    }

    @Override
    public void weave(OptimizerContext context, OptimizerVarAllocator allocator) {
        if (Debug.DEBUG) {
            Debug.checkAllocator(allocator, this);
        }
        OptimizerSnippets.filterReturnValue(context, allocator, target, filter);
    }
}
